


#ifndef PF_SNAPPER_H
#define PF_SNAPPER_H

#include "pf_entitycontainer.h"
#include "lx_Export.h"

#include "lx_define.h"
#include "pf_coordinateevent.h"

class PF_Entity;
class PF_GraphicView;
class PF_Vector;
class PF_Preview;
class QMouseEvent;

/**
 * This class is used for snapping functions in a graphic view. 
 * Actions are usually derrived from this base class if they need
 * to catch entities or snap to coordinates. Use the methods to
 * retrieve a graphic coordinate from a mouse coordinate.
 *
 * Possible snapping functions are described in PF_SnapMode.
 *

 */
class LX_EXPORT PF_Snapper {
public:
    PF_Snapper(PF_Container& container, PF_GraphicView& graphicView);
    virtual ~PF_Snapper();

    void init();
	void finish();

    /**
     * @return Pointer to the entity which was the key entity for the
     * last successful snapping action. If the snap mode is "end point"
     * the key entity is the entity whos end point was caught.
     * If the snap mode didn't require an entity (e.g. free, grid) this
     * method will return NULL.
     */
    PF_Entity* getKeyEntity() {
        return keyEntity;
    }

    /** Sets a new snap mode. */
    void setSnapMode(LX_Define::SnapMode snapMode) {
        this->snapMode = snapMode;
    }
    /** Sets a new snap restriction. */
    void setSnapRestriction(LX_Define::SnapRestriction snapRes) {
        this->snapRes = snapRes;
    }

	/** 
	 * Sets the snap range in pixels for catchEntity().
	 *
	 * @see catchEntity()
	 */
	void setSnapRange(int r) {
		snapRange = r;
	}

    PF_Vector snapPoint(QMouseEvent* e);

    PF_Vector snapFree(PF_Vector coord);
    PF_Vector snapEndpoint(PF_Vector coord);
    PF_Vector snapGrid(PF_Vector coord);
    PF_Vector snapOnEntity(PF_Vector coord);
    PF_Vector snapCenter(PF_Vector coord);
    PF_Vector snapMiddle(PF_Vector coord);
    PF_Vector snapDist(PF_Vector coord);
    PF_Vector snapIntersection(PF_Vector coord);
    //PF_Vector snapDirect(PF_Vector coord, bool abs);
	
    PF_Vector restrictOrthogonal(PF_Vector coord);
    PF_Vector restrictHorizontal(PF_Vector coord);
    PF_Vector restrictVertical(PF_Vector coord);

    //PF_Entity* catchLeafEntity(const PF_Vector& pos);
    //PF_Entity* catchLeafEntity(PF_MouseEvent* e);
    PF_Entity* catchEntity(const PF_Vector& pos,
                           LX_Define::ResolveLevel level=LX_Define::ResolveNone);
    PF_Entity* catchEntity(QMouseEvent* e,
                           LX_Define::ResolveLevel level=LX_Define::ResolveNone);

    /**
     * Suspends this snapper while another action takes place.
     */
    virtual void suspend() {
		//  Don't delete the snapper here!
        //   (can be deleted)();
        snapSpot = snapCoord = PF_Vector(false);
    }

    /**
     * Resumes this snapper after it has been suspended.
     */
    virtual void resume() {
        drawSnapper();
    }

    virtual void hideOptions();
    virtual void showOptions();

    void drawSnapper();

protected:
    void deleteSnapper();
    PF_Container* container;
    PF_GraphicView* graphicView;
    PF_Entity* keyEntity;
    PF_Vector snapCoord;
    PF_Vector snapSpot;
    LX_Define::SnapMode snapMode;
    LX_Define::SnapRestriction snapRes;
    /**
     * Snap distance for snaping to points with a 
     * given distance from endpoints.
     */
    double distance;
	/**
	 * Snap range for catching entities.
	 */
	int snapRange;
	/**
	 * Show large cross hairs.
	 */
	bool showCrosshairs;
	bool finished;
};

#endif
